const _ = require("lodash");
const fs = require("fs-extra");
const path = require("path");
const fsUtils = require("nodejs-fs-utils");
const schedule = require("node-schedule");
const prettyBytes = require("pretty-file-bytes");
const moment = require("moment");
const config = require("../config");
const util = require("../util");
// 每天 定时获取统计分析数据
schedule.scheduleJob("0 2 * * *", async (ctx, next) => {
  // 定义log数据数组
  const logArr = [];
  const baasIdList = await BaaS.Models.user_baas.query({}).fetchAll();
  // 获取应用列表id
  const baasIdArr = _.map(baasIdList, "baas_id");
  const baasList = await BaaS.Models.baas
    .query(qb => {
      qb.whereIn("id", baasIdArr);
    })
    .fetchAll();
  // 获取所有应用请求
  const baasIds = _.map(baasList, "id");
  requestList = await BaaS.Models.request
    .query(qb => {
      qb.whereIn("baas_id", baasIds);
      qb.where("created_at", ">=", `${moment().format("YYYY-MM-DD")} 00:00:00`);
    })
    .fetchAll();
  // 获取所有调试
  const debugList = await BaaS.Models.debug
    .query(qb => {
      qb.whereIn("baas_id", baasIds);
      qb.where(
        "created_at",
        ">=",
        `${moment()
          .subtract(1, "d")
          .format("YYYY-MM-DD")} 00:00:00`
      );
      qb.where("created_at", "<", `${moment().format("YYYY-MM-DD")} 00:00:00`);
    })
    .fetchAll();
  // 查询用户-应用信息列表
  const userInfoList = await BaaS.Models.user
    .query({})
    .fetchAll({ withRelated: ["user_info"] });
  for (const key in baasList) {
    // 查询用户信息
    let userBaas = "";
    let userInfo = "";
    for (const k in baasIdList) {
      if (baasIdList[k].baas_id == baasList[key].id) {
        userBaas = baasIdList[k];
      }
    }
    for (const k in userInfoList) {
      if (userInfoList[k].id == userBaas.user_id) {
        userInfo = userInfoList[k];
      }
    }
    // 统计该应用下的debug数量,request数量
    let debugNum = 0;
    for (const d in debugList) {
      if (baasList[key].id == debugList[d].baas_id) {
        debugNum += 1;
      }
    }
    // 统计请求数量
    let requestNum = 0;
    for (const r in requestList) {
      if (baasList[key].id == requestList[r].baas_id) {
        requestNum += 1;
      }
    }
    // 查询存储
    let fileSize = 0;
    const pathName = path.join(config.web, baasList[key].appid);
    await fs.ensureDir(pathName);
    try {
      // 获取文件大小
      let size = await new Promise((resolve, reject) => {
        async function getfileSize(pathName) {
          // 判断文件夹or文件
          const isDir = util.isDir(pathName);
          if (isDir) {
            const list = await fs.readdir(pathName);
            if (list.length) {
              for (const key in list) {
                const stat = await fs.lstat(path.resolve(pathName, list[key]));
                const isDir = stat.isDirectory();
                if (isDir) {
                  fileSize += parseFloat(
                    fsUtils.fsizeSync(path.join(pathName, list[key]))
                  );
                } else {
                  fileSize += parseFloat(
                    fsUtils.fsizeSync(path.resolve(pathName, list[key]))
                  );
                }
              }
            } else {
              fileSize += 0;
            }
          } else {
            fileSize += parseFloat(fsUtils.fsizeSync(pathName));
          }
          resolve(fileSize);
        }
        getfileSize(pathName);
      });
      // 遍历文件目录，叠加文件存储
      const fileList = await BaaS.Models.file
        .query({ where: { baas_id: baasList[key].id } })
        .fetchAll();
      for (const k in fileList) {
        if (baasList[key].id == fileList[k].baas_id) {
          size += fileList[k].size;
        }
      }
      // 查询流量费用
      let flow = 0;
      for (const k in requestList) {
        if (baasList[key].id == requestList[k].baas_id) {
          flow += util.format(requestList[k].length);
        }
      }
      flow = parseFloat(flow);
      const charges = await BaaS.Models.charges
        .query({
          where: { id: userBaas.charges_id }
        })
        .fetch();
      let deductPrice = 0;
      if (charges.id == 3) {
        // 计算存储费用
        const sizeGb = size / Math.pow(1024, 3);
        const storagePrice =
          Math.ceil(Math.pow(10, 4) * (sizeGb * charges.storage)) /
          Math.pow(10, 4);
        // 计算流量价格！
        const flowGb = parseFloat(flow / Math.pow(1024, 3));
        const flowPrice =
          Math.ceil(Math.pow(10, 4) * (flowGb * charges.flow)) /
          Math.pow(10, 4);
        // 计算APIcall费用
        const requestPrice = requestNum / 10000 * charges.request;
        // 合计要扣除的费用(流量，存储，云引擎)
        deductPrice = parseFloat(
          flowPrice +
            storagePrice +
            charges.engine * userBaas.engine +
            requestPrice
        ).toFixed(4);
      } else {
        // 判断用户是否超出套餐限额
        const sizeGb = prettyBytes(size, "GB");
        const flowGb = prettyBytes(flow, "GB");
        // 如果超出套餐，把应用状态改为0
        if (sizeGb > charges.storage || flowGb > charges.flow) {
          const redisKey = util.getAppKey(
            "baas",
            baasList[key].appid,
            baasList[key].appkey
          );
          await BaaS.redis.delAsync(redisKey);
          await BaaS.Models.charges.forge({ id: charges.id, status: 0 }).save();
        }
        deductPrice = charges.charges;
      }
      // 判断是否添加过记录，添加统计数据
      const logExist = await BaaS.Models.statistics
        .query(qb => {
          qb.where("baas_id", "=", baasList[key].id);
          qb.where(
            "created_at",
            ">",
            `${moment().format("YYYY-MM-DD")} 00:00:00`
          );
        })
        .fetch();
      // 扣除费用
      if (!logExist && userInfo) {
        userInfo = await BaaS.Models.user
          .forge({
            id: userInfo.id,
            money:
              Math.ceil(
                Math.pow(10, 4) * userInfo.money - Math.pow(10, 4) * deductPrice
              ) / Math.pow(10, 4)
          })
          .save();
        // 新增消费记录
        await BaaS.Models.cost_log
          .forge({
            user_id: userInfo.id,
            orderid: moment().format("YYMMDDHHmmssS") + util.randomCode(3),
            money: deductPrice,
            type: 1,
            status: 1,
            remark: "存储，流量，云引擎费用"
          })
          .save();
      }

      // 格式化存储格式
      storage = prettyBytes(size);
      // 格式化流量单位
      flow = prettyBytes(flow);

      const logItem = {
        baas_id: baasList[key].id,
        request_num: requestNum,
        storage: storage,
        debug: debugNum,
        flow: flow,
        date: moment()
          .subtract(1, "days")
          .format("YYYY-MM-DD")
      };
      Object.assign(logItem, { id: logExist.id });
      logArr.push(logItem);
    } catch (err) {
      console.log(err);
      return;
    }
  }
  // 添加统计记录
  await BaaS.bookshelf.Collection.extend({
    model: BaaS.Models.statistics
  })
    .forge(logArr)
    .invokeThen("save");
  // 遍历用户列表，余额不足的用户给予提醒
  for (const userInfo of userInfoList) {
    // 余额低于某个值，给用户发送提醒
    if (userInfo.money < config.noticeMoney) {
      const noticeAdd = await BaaS.Models.notice
        .forge({
          title: "余额不足",
          content: `您的余额仅剩${userInfo.money}，请尽快充值`
        })
        .save();
      await BaaS.Models.user_notice
        .forge({
          user_id: userInfo.id,
          notice_id: noticeAdd.id
        })
        .save();
      // 检测三天内登陆的用户发送短信
      if (
        userInfo.login_date &&
        moment(userInfo.login_date).format("YYYY-MM-DD") >
          moment()
            .subtract(3, "day")
            .format("YYYY-MM-DD")
      ) {
        util.sendSms(
          userInfo.phone,
          0,
          userInfo.user_info.nickname,
          userInfo.money,
          1
        );
      }
    }
  }
  console.log("定时任务执行完成");
});
